package tool.workflow.fsSoft

import akka.stream.Materializer
import akka.stream.scaladsl.Sink
import akka.util.ByteString
import command.CommandExec
import dao._
import implicits.Implicits._
import org.zeroturnaround.zip.ZipUtil
import play.api.i18n.Messages
import play.api.libs.ws.WSClient
import tool.Pojo._
import shared.Pojo._
import shared.pojo.WorkflowMission.EachPathwayAnaData
import shared.tool.DefaultPickle
import tool.plot.{EnrichBar, EnrichNetwork, PathwayBar, PathwayBubble, ZScore}
import tool.softT._
import tool.workflow.fsSoft.AllFsSoft.FSSoftBT
import tool.{FeatureSelectionTool, FormTool, Tool, plot}
import utils.Utils

import java.io.File
import scala.collection.immutable.SeqMap
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.language.postfixOps
import scala.concurrent.ExecutionContext.Implicits.global

/** Created by yz on 3/12/2020
  */
object FSPathwayAna extends FSSoftBT with AllSoftBT with PathwayAnaSoftT {

  override def getFileInfos(workspaceDir: File, index: Int)(implicit
      matrixFileDataDao: MatrixFileDataDao,
      messages: Messages
  ): List[FileInfoData] = {
    val subDir = new File(workspaceDir, s"pathwayAna_${index}")
    val iPathInfos = if (new File(subDir, "iPath3.svg").exists()) {
      List(
        FileInfoData("iPath3.svg", messages("iPath3"))
      )
    } else List[FileInfoData]()
    val networkInfos = if (new File(subDir, "Network.pdf").exists()) {
      List(
        FileInfoData("Network.pdf", messages("network")),
        FileInfoData("MSEA_Network.json", messages("mSEANetwork"))
      )
    } else List[FileInfoData]()
    (iPathInfos ::: List(
      FileInfoData("MSEA_Result.csv", messages("mSEAResult")),
      FileInfoData("Enrichment_Barplot.pdf", messages("enrichmentBarplot"))
    ) ::: networkInfos ::: List(
      FileInfoData("Pathway_Result.csv", messages("pathwayResult")),
      FileInfoData("Pathway_Bubbleplot.pdf", messages("pathwayBubbleplot")),
      FileInfoData("Pathway_Barplot.pdf", messages("pathwayBarplot")),
      FileInfoData("Sig_Pathways_ID.zip", messages("sigPathwaysID")),
      FileInfoData("Sig_Pathways_Name.zip", messages("sigPathwaysName"))
    )).filter { fileInfoData =>
      new File(subDir, fileInfoData.fileName).exists()
    }

  }

  def produceSubConfigFile(workspaceDir: File, data: EachPathwayAnaData) = {
    val subConfigFile = new File(workspaceDir, "calculate_config.json")
    DefaultPickle.write(data).toFile(subConfigFile)
  }

  override def produceInput(workspaceDir: File, resultDir: File, index: Int, parentNodeStr: String, id: String)(implicit
      dao: MyDao,
      messages: Messages
  ): Unit = {
    val groupFile = new File(workspaceDir.getParentFile, "group.txt")
    groupFile.fileCopyToDir(workspaceDir)
    FeatureSelectionTool.produceSubInputFile(workspaceDir, parentNodeStr)
    val data = FeatureSelectionTool.getFsData(workspaceDir.getParentFile).pathwayAna(index)
    produceSubConfigFile(workspaceDir, data)
    val rawDataFile = new File(workspaceDir, "AllMet_Raw.txt")
    val userIdR = "/user/(\\d+)/.*$".r
    val userId = userIdR
      .findFirstMatchIn(workspaceDir.unixPath)
      .map { matcher =>
        matcher.group(1)
      }
      .get
      .toInt
    Tool.produceKeggInfoFile(rawDataFile, workspaceDir)
  }

  override def getCommandData(workspaceDir: File, resultDir: File, index: Int): List[CommandData] = {
    val solutionFile = new File(Tool.dataDir, "color_solution/color_solution_1.txt")
    val groupFile = new File(workspaceDir, "group.txt")
    val inputMetabolites = Tool.inputMetabolites(workspaceDir)
    val command = if (inputMetabolites.nonEmpty) {
      s"""
         |${Tool.rScript} ${new File(Tool.rPath, "anno.R").unixPath}
         |${"Rscript".condaPath()} ${new File(Tool.rPath, "idMapping.R").unixPath} --d ${Tool.databaseDir.unixPath}
         |${"Rscript".condaPath()} ${new File(
          Tool.rPath,
          "enrich_id_mapping.R"
        ).unixPath} --d ${Tool.databaseDir.unixPath}
         |${"Rscript".condaPath()} ${new File(
          Tool.rPath,
          "enrich_analysis.R"
        ).unixPath} --d ${Tool.databaseDir.unixPath}
         |${"Rscript".condaPath()} ${new File(Tool.rPath, "kegg_enrich.R").unixPath} --d ${Tool.databaseDir.unixPath}
         |${"Rscript".condaPath()} ${new File(
          Tool.rPath,
          "pathway_layout_plot.R"
        ).unixPath} --d ${Tool.databaseDir.unixPath}
           """.stripMargin
    } else ""
    val plotCommands = List(
      plot.EnrichBar.getCommand(workspaceDir, "",convert = false),
      plot.PathwayBar.getCommand(workspaceDir, "",convert = false),
      plot.PathwayBubble.getCommand(workspaceDir, "",convert = false),
      plot.EnrichNetwork.getCommand(workspaceDir, "",convert = false),
    )
    List(CommandData(workspaceDir, List(command):::plotCommands))
  }

  override def resultDeal(workspaceDir: File, resultDir: File, index: Int)(implicit
      ws: WSClient,
      materializer: Materializer,
      messages: Messages
  ): Unit = {
    super.resultDeal(workspaceDir, resultDir, index)
    val data = FeatureSelectionTool.getFsData(workspaceDir.getParentFile).pathwayAna(index)
    val execIPath = data.execIPath
    if (execIPath) {
      val f = stepIPath(workspaceDir).map { x =>
        val svgFile = new File(workspaceDir, "iPath3.svg")
        Utils.svg2png(svgFile)
      }
      Utils.execFuture(f)
    }
    val outDirName = Tool.getTrueOutDir(idStr = workspaceDir.getName)
    val outDir = new File(resultDir, outDirName)
    Tool.resultDeal(workspaceDir, outDir)
    val idDir = new File(workspaceDir, "Sig_Pathways_ID")
    if (idDir.exists() && idDir.myListFiles.nonEmpty) {
      val idDestFile = new File(outDir, "Sig_Pathways_ID.zip")
      ZipUtil.pack(idDir, idDestFile)
    }
    val nameDir = new File(workspaceDir, "Sig_Pathways_Name")
    if (nameDir.exists() && nameDir.myListFiles.nonEmpty) {
      val nameDestFile = new File(outDir, "Sig_Pathways_Name.zip")
      ZipUtil.pack(nameDir, nameDestFile)
    }
    new File(workspaceDir, "MSEA_Network.json").fileCopyToDirIfExist(outDir)
    val needConvertFileNamePrefixs = List("Enrichment_Barplot", "Pathway_Bubbleplot", "Pathway_Barplot", "Network")
    val convertCommands = Tool.fileConvertCommandsIfExist(workspaceDir, needConvertFileNamePrefixs)
    CommandExec().exec { b =>
      CommandData(workspace = workspaceDir, commands = convertCommands, runFileName = "network_convert.sh")
    }
  }

  override def producePlotConfigFile(workspaceDir: File, index: Int): Any = {
    plot.EnrichBar.initConfigFile(workspaceDir, "")
    plot.PathwayBar.initConfigFile(workspaceDir, "")
    plot.PathwayBubble.initConfigFile(workspaceDir, "")
    plot.EnrichNetwork.initConfigFile(workspaceDir, "")
  }

  def stepIPath(workspaceDir: File)(implicit ws: WSClient, materializer: Materializer): Future[Unit] = {
    val startTime = System.currentTimeMillis()
    val nameFile = new File(workspaceDir, "name_map.txt")
    if (!nameFile.exists()) {
      return Future {
        println("error")
      }
    }
    val names = nameFile.lines.trimQuote.selectOneColumn("kegg").filter(_ != "NA").notEmptyLines
    if (names.size == 0) {
      return Future {
        println("error")
      }
    }
    val groupFile = new File(workspaceDir, "group.txt")
    val groupSize = groupFile.txtLines.selectOneColumn("classnote").distinct.notEmptyLines.size
    val fcFile = new File(workspaceDir, "fc_color.txt")
    val fcMap = fcFile.lines.lineMap.map { map =>
      val col = map("col")
      (map("kegg"), col)
    }.toMap
    val colorMap = fcMap.map { case (keggId, col) =>
      val webColor = col match {
        case "red" => "#FF0000"
        case "DeepSkyBlue" => "#00bfff"
        case "gold" => "#ffd700"
        case _ => ""
      }
      (keggId, webColor)
    }
    val nameStr = names
      .map { x =>
        val webColor = colorMap(x)
        List(x, webColor, "W20").mkString("\t")
      }
      .mkString("\n")
    val mapData = Map(
      "selection" -> nameStr,
      "default_opacity" -> 1.toString,
      "default_width" -> 3.toString,
      "default_radius" -> 7.toString,
      "default_color" -> "#666666",
      "background_color" -> "#ffffff",
      "tax_filter" -> "",
      "export_type" -> "svg",
      "export_dpi" -> 1200.toString,
      "include_microbial" -> 0.toString,
      "whole_pathways" -> 0.toString,
      "include_secondary" -> 0.toString,
      "whole_modules" -> 0.toString,
      "include_antibiotic" -> 0.toString,
      "keep_colors" -> 1.toString,
      "include_metabolic" -> 1.toString,
      "query_reactions" -> 0.toString
    )
    ws.url("https://pathways.embl.de/mapping.cgi")
      .withRequestTimeout(600 seconds)
      .post(mapData)
      .flatMap { response =>
        response.status match {
          case 200 =>
            val file = new File(workspaceDir, "iPath3.svg")
            val outputStream = java.nio.file.Files.newOutputStream(file.toPath)
            val sink = Sink.foreach[ByteString] { bytes =>
              outputStream.write(bytes.toArray)
            }
            response.bodyAsSource
              .runWith(sink)
              .andThen { case result =>
                outputStream.close()
                result.get
              }
              .map { x =>
                println(response)
                println(Utils.getTime(startTime))
              }
          case _ => Future {}
        }
      }
      .recover { case e: Exception =>
        e.printStackTrace()
        e.getMessage.toFile(new File(workspaceDir, "error.csv"))
      }

  }

}
